﻿using System;
using System.ComponentModel.Composition;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using DeepZoomPivotConstructor.ErrorAndLoggingInterfaces;
using DeepZoomPivotConstructor.VisualLib;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using RenderEngine;
using RenderEngineInterfaces;
using UriRenderer;

namespace t_UriRenderer
{
    /// <summary>
    /// Summary description for UnitTest1
    /// </summary>
    [TestClass]
    public class t_RenderUri
    {
        public t_RenderUri()
        {
        }

        private TestContext testContextInstance;

        /// <summary>
        ///Gets or sets the test context which provides
        ///information about and functionality for the current test run.
        ///</summary>
        public TestContext TestContext
        {
            get
            {
                return testContextInstance;
            }
            set
            {
                testContextInstance = value;
            }
        }

        [TestInitialize]
        public void InitForTest()
        {
            HttpAgentString = "Deeptalk library RenderUri Test";
            t_TestingLibrary.Utilities.MyClassInit();
            t_TestingLibrary.Utilities.AddPart(new RenderControl());
            t_TestingLibrary.Utilities.AddPart(new LayoutHelper());
            mylogger = new t_TestingLibrary.TestLogger();
            t_TestingLibrary.Utilities.AddPart(this);
            RenderingTempDir = null;
        }

        [Export(typeof(IErrorLogger))]
        private IErrorLogger mylogger;

        [Import]
        private IRenderEngine MyRender { get; set; }

        [TestCleanup]
        public void ShutDownTest()
        {
            t_TestingLibrary.Utilities.MyClassDone();
        }

        [TestMethod]
        public void TestSimpleCreate()
        {
            RenderUri ur = new RenderUri();
        }

        [TestMethod]
        public void TestCanRender()
        {
            RenderUri ur = new RenderUri();
            t_TestingLibrary.Utilities.Compose(ur);
            Assert.AreEqual(RenderPluginPriority.RPPGeneric, ur.RenderPriority(new Uri("http://www.nytimes.com")), "Rendering should be generic for almost any uri!");
        }

        [Export(typeof(IRenderItem))]
        [RenderInfo(typeof(FileInfo))]
        class RenderAFile : IRenderItem
        {
            public string ValidExt = ".pdf";
            public FileInfo FileRendered;

            public bool wasCalled = false;

            public System.Threading.Tasks.Task<Visual> Render(object what)
            {
                return Task<Visual>.Factory.StartNew(() =>
                    {
                        wasCalled = true;
                        FileRendered = what as FileInfo;
                        return new VisualBitmapImage(2.0, 3.0, 100, Color.Black);
                    });
            }

            public RenderPluginPriority RenderPriority(object what)
            {
                FileInfo f = what as FileInfo;
                if (f.Extension == ValidExt)
                {
                    return RenderPluginPriority.RPPGeneric;
                }

                if (ValidExt == "")
                {
                    return RenderPluginPriority.RPPGeneric;
                }

                return RenderPluginPriority.RPPCantDoIt;
            }
        }

        [Export("HttpAgentString")]
#pragma warning disable 0414
        private string HttpAgentString;
#pragma warning restore 0414

        [TestMethod]
        public void TestRenderPDF()
        {
            Uri u = new Uri("http://indico.cern.ch/getFile.py/access?contribId=s1t15&resId=1&materialId=0&confId=a042880");
            RenderAFile rfile = new RenderAFile();
            rfile.ValidExt = ".pdf";
            t_TestingLibrary.Utilities.AddPart(rfile);
            RenderUri ur = new RenderUri();
            t_TestingLibrary.Utilities.Compose(ur);

            var result = ur.Render(u);
            Assert.IsNotNull(result, "expected a future from that rendering");
            Assert.IsNotNull(result.Result, "Expecting a real visula from that!");
            Assert.AreEqual(1, result.Result.SGNodeList.Count, "Expected one image as background there!");
            Assert.IsTrue(rfile.wasCalled, "The rendering for the pdf file was never called!");
        }

        [TestMethod]
        public void TestWebSiteWithNoHEADER()
        {
            Uri u = new Uri("http://indico.ifca.es/indico/getFile.py/access?contribId=0&amp;sessionId=0&amp;resId=0&amp;materialId=slides&amp;confId=225");
            RenderAFile rfile = new RenderAFile();
            rfile.ValidExt = ".pdf";
            t_TestingLibrary.Utilities.AddPart(rfile);
            RenderUri ur = new RenderUri();
            t_TestingLibrary.Utilities.Compose(ur);

            var result = ur.Render(u);
            Assert.IsNotNull(result, "expected a future from that rendering");
            Assert.IsNotNull(result.Result, "Expecting a real visual from that rendering!");
        }

        [Export("RenderingTempDir")]
        private DirectoryInfo RenderingTempDir;

        [TestMethod]
        public void TestDownloadToLocalDir()
        {
            Uri u = new Uri("http://indico.cern.ch/getFile.py/access?contribId=s1t15&resId=1&materialId=0&confId=a042880");
            RenderAFile rfile = new RenderAFile();
            rfile.ValidExt = ".pdf";
            t_TestingLibrary.Utilities.AddPart(rfile);

            DirectoryInfo tempLoc = new DirectoryInfo(".\\TestDownloadToLocalDir)");
            if (tempLoc.Exists)
            {
                tempLoc.Delete();
            }
            tempLoc.Create();
            RenderingTempDir = tempLoc;

            RenderUri ur = new RenderUri();
            t_TestingLibrary.Utilities.Compose(ur);

            var result = ur.Render(u);
            var r = result.Result;
            Assert.AreEqual(1, tempLoc.EnumerateFiles().Count(), "Expected the file to have been downloaded in the temp directory!");
        }

        [TestMethod]
        public void TestRenderBogusWebFile()
        {
            Uri u = new Uri("http://www-d0.fnal.gov/fork.html");
            RenderAFile rfile = new RenderAFile();
            rfile.ValidExt = "";
            t_TestingLibrary.Utilities.AddPart(rfile);

            RenderUri ur = new RenderUri();
            t_TestingLibrary.Utilities.Compose(ur);

            var result = ur.Render(u);
            Assert.IsNotNull(result, "expected a future from that rendering");
            Assert.IsNull(result.Result, "Not expecting a real visula from that!");
            Assert.IsFalse(rfile.wasCalled, "The render for the pdf file should never have been called!");
        }

        [TestMethod]
        public void TestMetadata()
        {
            Uri u = new Uri("http://indico.cern.ch/getFile.py/access?contribId=s1t15&resId=1&materialId=0&confId=a042880");
            RenderAFile rfile = new RenderAFile();
            rfile.ValidExt = ".pdf";
            t_TestingLibrary.Utilities.AddPart(rfile);

            t_TestingLibrary.Utilities.Compose(new RenderUri());

            var result = MyRender.Render(u);
            Assert.IsNotNull(result, "expected a future from that rendering");
            Assert.AreEqual(1, result.SGNodeList.Count, "Expected one image as background there!");
            Assert.IsTrue(rfile.wasCalled, "The rendering for the pdf file was never called!");
        }

        [TestMethod]
        public void TestFailsWithFTP()
        {
            Uri u = new Uri("ftp://www.fnal.gov/dude.forkitover");
            var r = new RenderUri();
            Assert.AreEqual(RenderPluginPriority.RPPCantDoIt, r.RenderPriority(u), "Render should not be able to do a ftp URI!");
        }

        [TestMethod]
        public void TestJPEGFile()
        {
            Uri u = new Uri("http://d0server1.fnal.gov/projects/spokes/d0_logos/logo-white-small.jpg");
            RenderAFile rfile = new RenderAFile() { ValidExt = ".jpg" };
            t_TestingLibrary.Utilities.AddPart(rfile);
            t_TestingLibrary.Utilities.Compose(new RenderUri());

            var result = MyRender.Render(u);
            Assert.IsNotNull(result, "Expecting a future from that render!");
            Assert.AreEqual(1, result.SGNodeList.Count, "Expected one image as background there!");
            Assert.IsTrue(rfile.wasCalled, "Rendering for the jpeg was never called!");
        }

        [TestMethod]
        public void TestJPEGFile2()
        {
            /// sometimes it is jpg and sometimes jpeg...
            Uri u = new Uri("http://www-d0.fnal.gov/Run2Physics/WWW/results/prelim/TOP/T82/thumbnails/T82F1.jpeg");
            RenderAFile rfile = new RenderAFile() { ValidExt = ".jpg" };
            t_TestingLibrary.Utilities.AddPart(rfile);
            t_TestingLibrary.Utilities.Compose(new RenderUri());

            var result = MyRender.Render(u);
            Assert.IsNotNull(result, "Expecting a future from that render!");
            Assert.AreEqual(1, result.SGNodeList.Count, "Expected one image as background there!");
            Assert.IsTrue(rfile.wasCalled, "Rendering for the jpeg was never called!");
        }

        [TestMethod]
        public void TestPNGFile()
        {
            Uri u = new Uri("http://www-d0.fnal.gov/hardware/dfe/dps/dps.png");
            RenderAFile rfile = new RenderAFile() { ValidExt = ".png" };
            t_TestingLibrary.Utilities.AddPart(rfile);
            t_TestingLibrary.Utilities.Compose(new RenderUri());

            var result = MyRender.Render(u);
            Assert.IsNotNull(result, "Expecting a future from that render!");
            Assert.AreEqual(1, result.SGNodeList.Count, "Expected one image as background there!");
            Assert.IsTrue(rfile.wasCalled, "Rendering for the jpeg was never called!");
        }

        [TestMethod]
        public void TestPNGFileWithOddDPI()
        {
            Uri u = new Uri("https://twiki.cern.ch/twiki/pub/Atlas/MuonPerformancePublicPlotsSimulation/FIG5.png");
            RenderAFile rfile = new RenderAFile() { ValidExt = ".png" };
            t_TestingLibrary.Utilities.AddPart(rfile);
            t_TestingLibrary.Utilities.Compose(new RenderUri());

            var result = MyRender.Render(u);
            Assert.IsNull(result, "Expected to render to null - this image has a bad DPI setting");
#if false
            Assert.IsNotNull(result, "Expecting a future from that render!");
            Assert.AreEqual(1, result.SGNodeList.Count, "Expected one image as background there!");
            Assert.IsTrue(rfile.wasCalled, "Rendering for the png was never called!");

            var pngFIle = rfile.FileRendered;
            Assert.IsTrue(pngFIle.Exists, "Downloaded file should exist!");
            var img = Image.FromFile(pngFIle.FullName);
            Assert.AreEqual(img.HorizontalResolution, img.VerticalResolution, "Expected same resolution on each axis!");
#endif
        }

        [TestMethod]
        public void TestGIFFile()
        {
            Uri u = new Uri("http://www-d0.fnal.gov/phys_id/jes/public/plots_v7.1/jes_correction.gif");
            RenderAFile rfile = new RenderAFile() { ValidExt = ".gif" };
            t_TestingLibrary.Utilities.AddPart(rfile);
            t_TestingLibrary.Utilities.Compose(new RenderUri());

            var result = MyRender.Render(u);
            Assert.IsNotNull(result, "Expecting a future from that render!");
            Assert.AreEqual(1, result.SGNodeList.Count, "Expected one image as background there!");
            Assert.IsTrue(rfile.wasCalled, "Rendering for the gif was never called!");
        }

        [TestMethod]
        public void TestRenderCompareGood()
        {
            RenderUri r = new RenderUri();
            Assert.IsNotNull(r as IRenderableObjectCompare, "RenderUri is not implementing Render Object Compare!");
        }

        [TestMethod]
        public void TestRenderHash()
        {
            Uri u1 = new Uri("http://www.nytimes.com");
            Uri u2 = new Uri("http://www.cnn.com");
            Uri u3 = new Uri("http://www.nytimes.com");

            IRenderableObjectCompare cmp = new RenderUri();

            long h1 = cmp.GetObjectHash(u1);
            long h2 = cmp.GetObjectHash(u2);
            long h3 = cmp.GetObjectHash(u3);

            Assert.AreNotEqual(h1, h2, "The hashes should be different between the two uri's!");
            Assert.AreEqual(h1, h3, "THe same uri, should be the same!");
        }

        [TestMethod]
        public void TestRenderHashByPage()
        {
            Uri u1 = new Uri("http://www.nytimes.com");
            Uri u2 = new Uri("http://www.nytimes.com/fork.html");

            IRenderableObjectCompare cmp = new RenderUri();

            long h1 = cmp.GetObjectHash(u1);
            long h2 = cmp.GetObjectHash(u2);

            Assert.AreNotEqual(h1, h2, "The hashes should be the same!");
        }

        [TestMethod]
        public void TestObjectCompare()
        {
            Uri u1 = new Uri("http://www.nytimes.com");
            Uri u2 = new Uri("http://www.cnn.com");
            Uri u3 = new Uri("http://www.nytimes.com");

            IRenderableObjectCompare cmp = new RenderUri();

            Assert.IsFalse(cmp.ObjectsEqual(u1, u2), "The hashes should be different!");
            Assert.IsTrue(cmp.ObjectsEqual(u1, u3), "THe same uri, should be the same!");
        }

        [TestMethod]
        public void TestGetObjectMetaData()
        {
            Uri u1 = new Uri("https://atlas.web.cern.ch/Atlas/GROUPS/PHYSICS/CONFNOTES/ATLAS-CONF-2010-006/fig_01.png");
            IRenderableObjectCompare cmp = new RenderUri();
            object meta = cmp.GetObjectDateMetaData(u1);
            Assert.IsNotNull(meta, "Meta data should be zero!");
            long mint = (long)meta;
            Assert.AreNotEqual(0, mint, "The meta data should not be zero!");
        }

        [TestMethod]
        public void TestObjectOutOfDate()
        {
            Uri u1 = new Uri("https://atlas.web.cern.ch/Atlas/GROUPS/PHYSICS/CONFNOTES/ATLAS-CONF-2010-006/fig_01.png");
            Uri u2 = new Uri("https://atlas.web.cern.ch/Atlas/GROUPS/PHYSICS/CONFNOTES/ATLAS-CONF-2010-015/fig_01a.png");
            IRenderableObjectCompare cmp = new RenderUri();
            object meta1 = cmp.GetObjectDateMetaData(u1);
            object meta2 = cmp.GetObjectDateMetaData(u2);

            /// u1 should be older than u2...


            Assert.IsTrue(cmp.IsOutOfDate(u2, meta1), "Expected u2 to be older than u1!");
            Assert.IsFalse(cmp.IsOutOfDate(u1, meta2), "Expected u1 to be younger than u2!");
        }

        [TestMethod]
        public void TestObjectOutOfDataNullMetadata()
        {
            Uri u1 = new Uri("https://atlas.web.cern.ch/Atlas/GROUPS/PHYSICS/CONFNOTES/ATLAS-CONF-2010-006/fig_01.png");
            IRenderableObjectCompare cmp = new RenderUri();
            Assert.IsFalse(cmp.IsOutOfDate(u1, null), "Expected u1 not to be out of date with null meta data!");
        }

        [TestMethod]
        public void TestUriMetadataFromCDSFigureImage()
        {
            Uri u1 = new Uri("http://cdsweb.cern.ch/record/1237408/files/Figure_002a.pdf");
            IRenderableObjectCompare cmp = new RenderUri();

            object metadata = cmp.GetObjectDateMetaData(u1);
            long timeInTicks = (long)metadata;
            Trace.WriteLine("Read back a trace of " + timeInTicks);

            DateTime theDate = new DateTime(timeInTicks).ToUniversalTime();

            Trace.WriteLine("Output date is " + theDate.Month + "/" + theDate.Day + "/" + theDate.Year);
            Trace.WriteLine("Output time is " + theDate.Hour + ":" + theDate.Minute + ":" + theDate.Second);

            Assert.AreEqual(2010, theDate.Year, "Year is incorrect");
            Assert.AreEqual(9, theDate.Day, "The day is wrong");
            Assert.AreEqual(3, theDate.Month, "The month si wrong");

            Assert.AreEqual(16, theDate.Hour, "The hour is wrong");
            Assert.AreEqual(32, theDate.Minute, "The minus is wrong");
            Assert.AreEqual(34, theDate.Second, "The seconds are wrong!");
        }

        [TestMethod]
        public void TestDownloadModifiedDate()
        {
            ///
            /// The downloaded file should have the "proper" date.
            /// 

            Uri u = new Uri("https://indico.cern.ch/getFile.py/access?contribId=3&sessionId=57&resId=1&materialId=slides&confId=35523");
            RenderAFile rfile = new RenderAFile() { ValidExt = ".pdf" };
            t_TestingLibrary.Utilities.AddPart(rfile);
            t_TestingLibrary.Utilities.Compose(new RenderUri());

            MyRender.Render(u);
            Assert.IsTrue(rfile.FileRendered.Exists, "File downloaded doesn't exist!");
            var lastMod = rfile.FileRendered.LastWriteTime;

            Assert.AreEqual(2009, lastMod.Year, "Year of last mod is incorrect");
            Assert.AreEqual(3, lastMod.Month, "Month of last mod is incorrect");
            Assert.AreEqual(20, lastMod.Day, "Day of last mod time is incorrect");
        }

        [TestMethod]
        public void TestGetMetaObjectForNoneDateDude()
        {
            ///
            /// Some web servers don't return a last-modified date. Make sure that we substitute in the content length for it
            /// 

            Uri u = new Uri("http://www.er.doe.gov/hep/files/pdfs/Brinkman_HEPAP_Presentation01-clean.pdf");

            RenderUri uRender = new RenderUri();

            var result = uRender.GetObjectDateMetaData(u);
            Assert.IsNotNull(result, "Render object meta data for a server that doesn't return a modified date should not be null!");
        }
    }
}
